﻿using System;
using System.Collections.Generic;
using System.Data;

namespace Jasmine.Extensions.Lists
{
    public static class ListExtension
    {
        /// <summary>
        /// Adds elements from the specified collection to the list if they do not already exist in the list.
        /// </summary>
        /// <remarks>This method uses the list's <see cref="List{T}.Contains(T)"/> method to determine
        /// whether an element already exists. For large lists or types with expensive equality checks, performance may
        /// be affected. The method does not add duplicate elements from the input collection if they already exist in
        /// the list.</remarks>
        /// <typeparam name="T">The type of elements contained in the list and the collection to add.</typeparam>
        /// <param name="list">The list to which unique elements will be added. Cannot be null.</param>
        /// <param name="items">The collection of elements to add to the list. Elements that already exist in the list are ignored. Cannot
        /// be null.</param>
        public static void AddRangeIfNotExists<T>(this List<T> list, IEnumerable<T> items)
        {
            foreach (var item in items)
            {
                if (!list.Contains(item))
                {
                    list.Add(item);
                }
            }
        }

        /// <summary>
        /// Converts a list of objects to a DataTable, with each object's public properties represented as columns.
        /// </summary>
        /// <remarks>Property values that are null are represented as DBNull in the resulting DataTable.
        /// Only public instance properties are included as columns. The DataTable's name is set to the name of type
        /// T.</remarks>
        /// <typeparam name="T">The type of objects contained in the list. Each public property of this type will be mapped to a column in
        /// the resulting DataTable.</typeparam>
        /// <param name="items">The list of objects to convert to a DataTable. Each object in the list will be represented as a row.</param>
        /// <returns>A DataTable containing one row for each object in the list, with columns corresponding to the public
        /// properties of type T. If the list is empty, the DataTable will contain no rows.</returns>
        public static DataTable ToDataTable<T>(this List<T> items)
        {
            var dataTable = new DataTable(typeof(T).Name);
            // Get all the properties
            var properties = typeof(T).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
            // Create columns in the DataTable for each property
            foreach (var prop in properties)
            {
                dataTable.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
            }
            // Populate the DataTable with data from the list
            foreach (var item in items)
            {
                var values = new object[properties.Length];
                for (int i = 0; i < properties.Length; i++)
                {
                    values[i] = properties[i].GetValue(item) ?? DBNull.Value;
                }
                dataTable.Rows.Add(values);
            }
            return dataTable;
        }


    }
}
